/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.spi.jsonser.abstractcefchange;

import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
import com.inspur.edp.cef.api.manager.serialize.CefSerializeContext;
import com.inspur.edp.cef.entity.changeset.AbstractModifyChangeDetail;
import com.inspur.edp.cef.entity.config.SerializerUtils;
import com.inspur.edp.cef.entity.entity.ICefData;

import com.inspur.edp.cef.entity.entity.IMultiLanguageData;
import com.inspur.edp.cef.entity.i18n.MultiLanguageInfo;
import com.inspur.edp.cef.spi.extend.IDataExtendSerializerItem;
import com.inspur.edp.cef.spi.extend.entity.ICefEntityExtend;
import com.inspur.edp.cef.spi.jsonser.entity.AbstractEntitySerializerItem;
import java.io.IOException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public  abstract class AbstractCefDataDeSerializer<T extends com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefDataSerItem> extends JsonDeserializer<ICefData> {
    protected java.util.List<T> deSerializers;
    protected AbstractCefDataDeSerializer(java.util.List<T> serializers)
    {
        this.deSerializers = serializers;
    }

    private java.util.List<T> serItems;

    protected java.util.List<T> getSerializerItems() {
        if (serItems == null) {
            serItems = deSerializers;
            if (extendList != null) {
                serItems.addAll(extendList.stream().map(item -> (T) item.getSerializerItem())
                    .filter(item -> item != null).collect(
                        Collectors.toList()));
            }
        }
        return serItems;
    }

    @Override
    public ICefData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        return readJson(p,ctxt);
    }

    public final ICefData readJson(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (p.getCurrentToken() != JsonToken.START_OBJECT)
        {
            throw new RuntimeException("json结构异常");
        }
        p.nextToken();
        ICefData data = createData(p);
        while (p.hasCurrentToken())
        {
            if (p.getCurrentToken() == JsonToken.END_OBJECT)
            {
                break;
            }
            if(p.getCurrentToken() != JsonToken.FIELD_NAME){
                p.nextToken();
                continue;
            }

            String propertyName = p.getValueAsString();
            p.nextToken();
            if(!readMultiLanguageInfo(p, ctxt, data, propertyName)) {
                readDataInfo(p, ctxt, data, propertyName);
                p.nextToken();
            }
        }
        return data;
    }

    protected abstract ICefData createData(JsonParser p);

    protected void readDataInfo(JsonParser p, DeserializationContext ctxt, ICefData data, String propertyName)
    {
        boolean hasRead = false;

        for (com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefDataSerItem item : getSerializerItems())
        {
            if (item instanceof IDataExtendSerializerItem
                && !org.springframework.util.StringUtils.isEmpty(configId)) {
                ((IDataExtendSerializerItem) item).setConfigId(configId);
            }
            if (item.readEntityBasicInfo(p,ctxt, data, propertyName))
            {
                hasRead = true;
                break;
            }
        }
        if(!hasRead && p.getCurrentToken() == JsonToken.START_OBJECT){
            readObject(p);
        }
    }

    //TODO: 挪到MultiLangSerializationUtil
    private boolean readMultiLanguageInfo(JsonParser p,DeserializationContext ctxt,
        ICefData detail, String propertyName) {
        boolean hasRead = false;
        if (detail instanceof IMultiLanguageData && propertyName != null && propertyName.endsWith(MultiLanguageInfo.MULTILANGUAGETOKEN)) {
            String webPropertyName = propertyName.split(MultiLanguageInfo.MULTILANGUAGETOKEN)[0];
            String bffPropertyName = "";
            for (AbstractCefDataSerItem item : getSerializerItems()) {
                if (item instanceof AbstractEntitySerializerItem) {
                    AbstractEntitySerializerItem entitySerializerItem = (AbstractEntitySerializerItem) item;
                    Map<String, String> propertyNameMap = entitySerializerItem
                        .getTransferPropertyNameMap();
                    if (propertyNameMap == null)
                        continue;
                    if (propertyNameMap.containsKey(webPropertyName)) {
                        bffPropertyName = entitySerializerItem.getTransferPropertyNameMap()
                            .get(webPropertyName) + MultiLanguageInfo.MULTILANGUAGETOKEN;
                        break;
                    } else {
                        for (Map.Entry<String, String> mapItem:propertyNameMap.entrySet())
                        {
                            if(mapItem.getKey().equalsIgnoreCase(webPropertyName))
                                bffPropertyName = mapItem.getValue() + MultiLanguageInfo.MULTILANGUAGETOKEN;
                        }
                    }
                }
            }
            if (bffPropertyName.isEmpty()) {
                throw new RuntimeException("变更集中的多语属性名无法识别：" + propertyName);
            }
            ((IMultiLanguageData)detail).getMultiLanguageInfos()
                .put(bffPropertyName, readMultiLanguageInfo(p, bffPropertyName));
            hasRead = true;
        }
        return hasRead;
    }

    private MultiLanguageInfo readMultiLanguageInfo(JsonParser parser, String propName) {
        MultiLanguageInfo info = new MultiLanguageInfo();
        info.setPropName(propName);
        try {
            SerializerUtils.readStartObject(parser);
            while (parser.getCurrentToken() == FIELD_NAME) {
                String language = SerializerUtils.readPropertyName(parser);
                String value = SerializerUtils.readPropertyValue_String(parser);
                info.getPropValueMap().put(language, value);
            }
            SerializerUtils.readEndObject(parser);
            return info;
        } catch (RuntimeException e) {
            throw new RuntimeException("反序列化MultiLanguageInfo类型失败", e);
        }
    }

    private void readObject(JsonParser p){

        JsonToken currentToken = p.getCurrentToken();
        if(currentToken != JsonToken.START_OBJECT)
            return;
        int index = 1;
        while (index > 0){
            try {
                p.nextToken();
            } catch (IOException e) {
                throw new RuntimeException("反序列化失败，Json结构异常:"+p.toString(), e);
            }
            if(p.getCurrentToken() == JsonToken.START_OBJECT){
                index ++;
                continue;
            }
            if(p.getCurrentToken() == JsonToken.END_OBJECT){
                index --;
                continue;
            }
        }

    }
    ///#region Read
    /**
     读取字符数据

     @param p 值
     @return 得到的字符串值
     */
    protected final String readString(JsonParser p) throws IOException {
        return p.getValueAsString();

    }

    /**
     读取整型数据

     @param p 值
     @return 得到的整数值
     */
    protected final int readInt(JsonParser p) throws IOException
    {
        return p.getValueAsInt();
    }

    /**
     读取小数数据

     @param p 值
     @return 得到的小数值
     */
    protected final double readDecimal(JsonParser p) throws IOException
    {
        return p.getValueAsDouble();
    }

    /**
     读取布尔数据

     @param p 值
     @return 得到的布尔值
     */
    protected final boolean readBool(JsonParser p) throws IOException
    {
        return p.getValueAsBoolean();
    }
    /**
     读取日期数据

     @param p 值
     @return 得到的日期值
     */
    protected final java.util.Date readDateTime(JsonParser p) throws IOException
    {
        String strValue =p.getValueAsString();
        if(strValue!=null&&strValue!="")
            return Date.valueOf(strValue);
        else {
            return null;
        }

    }
    /**
     读取二进制数据

     @param p 值
     @return 得到的二进制数据值
     */
    protected final byte[] readBytes(JsonParser p) throws IOException
    {
        throw new UnsupportedOperationException();
        //Jaav版临时屏蔽
//        return Convert.FromBase64String(String.valueOf(value));
    }

    /**
     读取枚举数据

     @param p 值
     @return 得到的枚举值
     */
    protected final <T> T readEnum(JsonParser p) throws IOException
    {
        throw new UnsupportedOperationException();
        //Java版临时屏蔽
//        return T.valueOf(String.valueOf(value));
    }
    /**
     读取关联数据

     @param p 值
     @return 得到的关联值
     */
    protected final <T> T readAssociation(JsonParser p) throws IOException
    {
        throw new UnsupportedOperationException();
        //Java版临时屏蔽
//        p.readValueAs(Class<T>);
//        return ((JToken)((value instanceof JToken) ? value : null)).<T>ToObject();
    }

    private String configId;
    @Deprecated
    public void setConfigId(String value){
        configId = value;
    }

    private List<ICefEntityExtend> extendList;

    public void addExtend(ICefEntityExtend extList){
        Objects.requireNonNull(extList);

        if(extendList == null){
            extendList = new ArrayList<>();
        }
        extendList.add(extList);
    }

    protected List<ICefEntityExtend> getExtendList(){
        return extendList == null ? Collections.emptyList() : extendList;
    }

    public void setCefSerializeContext(CefSerializeContext context) {
        if (this.deSerializers != null && this.deSerializers.size() > 0) {
            for (T item : deSerializers
            ) {
                item.setCefSerializeContext(context);
            }
        }
    }
}
